## これは何?
5ch.netからdatを取得し、クライアントに返すプロクシです。 
接続先が\*.2ch.netの場合、内部でURLを\*.5ch.netに変換した上で接続を行います。

## 使い方
起動し、各ブラウザのプロクシ設定を変更してください。デフォルトではポート9080で接続を受け付けます。以下のオプションが指定可能です。

* `-p port1[,port2,...]`

	待ち受けするポート番号を指定します。デフォルトは9080です。カンマ区切りで複数指定することが可能です。

* `-t timeout`

	タイムアウト(秒) を指定します。デフォルトは30秒です。

* `-a user-agent`

	proxy2chからリクエストを行う際の`User-Agent`ヘッダを指定した値で上書きします。指定しない場合はクライアントがヘッダに付与した値がそのまま送信されます。

* `-g`

	全ての接続を受け付けます。これを指定しない場合は、同じマシンから`localhost(127.0.0.1)`への接続のみを受け付けます。

* `-c`

	`HTTP CONNECT`リクエストを受け付けます。httpsなプロクシとして動作するようになりますが、このオプション単体ではリクエストの改変は行えないので透過的なプロクシとしてのみ機能します。

* `-4`

	強制的にIPv4で接続します。

* `--proxy server:port`

	プログラムが使うプロクシサーバを指定します。  
	`socks4://192.168.1.1:1080`のように頭に`socks4://`や`socks5://`を付けると、socksプロクシを指定できます。

* `-b backlog`

	listen関数で接続を待ち受けるソケットのbacklogの値を指定します。デフォルトは32です。

* `-s`

	\*.2ch.net, \*.5ch.net, \*.bbspink.comドメインへの接続をhttpsで行います。kako.5ch.netサーバ上にあるログを取得するためにはこのオプションが必要です。

* `-k`

	httpsなURLに接続するときにサーバの証明書の検証を行わないようにします。

* `--api AppKey:HmacKey`

	このオプションを指定すると、5ch/bbspink/talkの読み書きにAPIを利用しますが、5ch/bbspinkは2023年7月10日をもってAPIを利用しないdatの直接取得が復活したため、このオプションを指定する意味があるのはtalkの読み書きをしたい場合のみです。

* `--api-usage read|post|all|postinclpink|allinclpink|talk`

	`--api`オプションが指定されたときにAPIを使う用途を指定します。`talk`を指定する場合はtalkの読み書きにAPIを使います。現在は`talk`以外の値を指定する意味はありませんが、`read`を指定すると5chの読み込みのみ、`post`を指定すると5chの書き込みのみ、`all`を指定すると5chの読み書き両方にAPIを使います。デフォルト値は`all`です。`postinclpink`あるいは`allinclpink`を指定することでbbspinkへの書き込みにもAPIを使うことができます。

* `--api-auth-ua user-agent`
* `--api-dat-ua user-agent`

	APIのSID取得時、dat取得時の`User-Agent`ヘッダの値を指定します。

* `--api-auth-xua X-2ch-UA`
* `--api-dat-xua X-2ch-UA`

	APIのSID取得時、dat取得時の`X-2ch-UA`ヘッダの値を指定します。

* `--api-auth-header "header: value"`
* `--api-dat-header "header: value"`

	APIのSID取得時、dat取得時の任意のリクエストヘッダを指定します。

* `--api-server server`

	APIのゲートウェイサーバを指定します。デフォルト値はapi.5ch.netもしくはapi.talk-platform.comです。

* `--api-override`

	APIを使ったdat取得リクエストを受け取った場合、proxy2chがAPIサーバの代わりに取得して返すようになります。MITMが有効になっていなくてもオプション自体は有効ですが、APIリクエストは基本的にhttpsで来るはずなのでMITM前提です。

* `--chunked`

	素通しする接続に対して、`Transfer-Encoding: chunked`なレスポンスをchunkedなまま送り返します。  
	SofTalk WEBというソフトがこのオプションを指定しないと動かないようです。

* `--verbose`

	多少詳しくログを表示します。

* `--bbsmenu URL`

	URLで指定したアドレスを板リストとみなし、HTMLのリンク中に出現する"5ch.net"の文字列を"2ch.net"に、"https://"を"http://"にそれぞれ置換します。

* `--bbscgi-header "header: value"`

	5ch/bbspinkのbbs.cgiに接続要求する際、指定したheaderのリクエストヘッダの値をvalueに上書き (存在しない場合は追加) します。オプションを複数指定することで複数のヘッダを書き換えることができます。 
	valueの部分に`%HOST%`もしくは`%BOARD%`もしくは `%THREAD%`という文字列が含まれている場合、`%HOST%`はリクエスト先URLのホスト名に、`%BOARD%`はリクエストボディから取得した掲示板の名前に、`%THREAD%`はリクエストボディから取得したスレッドのkeyにそれぞれ置き換えられます。

* `--bbscgi-postorder "field1,field2,..."`

	5ch.netのbbs.cgiに接続要求する際、指定した順序にリクエストボディのフィールドを並べ替えます。順序はカンマ区切りでフィールド名を指定してください。指定しなかったフィールドは指定したものの後に続きます。

* `--bbscgi-utf8 none|api|all`

	5ch/bbspinkのbbs.cgiにPOSTされるリクエストボディを (Shift JISから) UTF-8に変換するかどうかを指定します。`none`を指定すると変換は行われません。`api`を指定すると`--api`オプションによって書き込みにAPIが使用されるときにのみ変換が行われます。`all`を指定するとAPIが使用されるかによらず変換が行われます。デフォルト値は`api`です。なお、`all`を指定した場合でもLuaスクリプトでAPI関係のヘッダが追加された場合には (署名が不一致になる可能性があるため) 変換はスキップされます。
	変換元のリクエストボディが既にUTF-8になっていると思われる場合はそのまま送信されますが、その場合も含めて`Content-Type`ヘッダに`application/x-www-form-urlencoded; charset=UTF-8`という値が暗黙のうちにセットされます。

* `--bbscgi-lua path`

	5ch/bbspinkの`bbs.cgi`に`POST`リクエストが送られる直前にproxy2chから呼び出されるLuaスクリプトのパスを指定します。  
	このスクリプトに`willSendRequestToBbsCgi`という関数を定義することにより、proxy2chが`bbs.cgi`に対して送るリクエストヘッダ/ボディを自由に改変することができます。詳しくは[サンプルスクリプト](https://notabug.org/NanashiNoGombe/proxy2ch/src/master/lua/sample.lua)を参照してください。  
	`--bbscgi-header`オプションと同時に指定した場合、まず`--bbscgi-header`オプションによりヘッダの改変が行われ、その後にこのオプションで指定したスクリプトが実行されます。

* `--bbscgi-confirmation auto|skip|none`

	5chに投稿する際に表示される確認画面への対応方法を指定します。`auto`はブラウザには投稿確認画面が表示されますが、ブラウザからのリクエストに介入してサーバに受理される正しいフォームを送るように修正を行います。`skip`はブラウザには投稿確認画面は表示されなくなり、proxy2chが確認処理を代行します。`none`は全てをブラウザ側に任せてproxy2chは何も行いません。デフォルトは`auto`です。

* `--bbscgi-fix-timestamp`

	5ch/bbspinkのbbs.cgiにPOSTする前に`time`フィールドの値を現在時刻の10秒前に修正します。

* `--manage-bbscgi-cookies`

	5ch/bbspinkへの投稿に関係するクッキーをproxy2ch側で管理/処理します。

* `--gikofix`

	古いギコナビで5ch.netに書き込めない問題を解消します。bbs.cgiにPOSTする際のbody末尾の余計な改行を取り除きます。

* `--mitm minimal|all`

	`-c`オプションと同時に指定することでいわゆるMITM proxyとして動作するようになります。`--mitm minimal`とすると5ch.netやbbspink.com等proxy2chが介入する可能性のあるドメインへの接続のみMITMを行い、`--mitm all`とすると全てのHTTP CONNECTで受け取った接続に対してMITMを行います。

* `--mitm-ca-cert path`

	MITMモードでサーバ証明書の署名に使う**PEM形式の**(自己署名)認証局証明書を指定します。

* `--mitm-ca-key path`

	MITMモードでサーバ証明書の署名に使う**PEM形式でパスフレーズなしの**秘密鍵を指定します。

* `--mitm-certgen`

	`--mitm-ca-cert`と`--mitm-ca-key`で使える自己署名CA証明書 (有効期限3年) と秘密鍵を生成してPEM形式で標準出力に出力して終了します。

* `--num-threads #threads`

	スレッドプール内で待機させるスレッド数を指定します。デフォルト値は8です。

* `--keystore path`

	`--manage-bbscgi-cookies`オプションを指定したときのクッキーと、APIを使った書き込み時に払い出されたMonaKeyを保存するJSONファイルのパスを指定します。このオプションを指定するとクッキーやMonaKeyが更新された時にパスのファイルが作成・更新され、proxy2ch起動時にファイルから復元されるようになります。

* `--no-direct-dat`

	dat取得リクエストを受け取った時、read.cgiの出力を加工して返します。このオプションを指定しない場合は`/板名/dat/***.dat` (現行ログ) あるいは`/板名/oyster/***/***.dat` (過去ログ) にあるファイルを直接取得して返します。

* `--subject-to-lastmodify [host1,host2,...]`

	5ch/bbspinkのsubject.txtを取得するリクエストを受け取った時、指定したホストについてlastmodify.txtから生成して返します。ホストを指定しない場合は全てのホストが対象になります。

* `--tls-max version`

	libcurlでhttps接続する際に使われるTLSの最大バージョンを指定します。1.0/1.1/1.2/1.3のいずれかの値が有効です。

* `--tls-backend name`

	libcurlで複数のTLSバックエンドがサポートされている場合、利用するものを選択します。無効な値を指定した場合はバックエンドの一覧が表示されます。

* `--ca-bundle path`

	httpsなURLに接続するときにサーバ証明書の検証に使うCA証明書のバンドルのパスを指定します。`@curl`を指定するとlibcurlビルド時に決まる既定のパスを使います。`@system`を指定すると`@curl`のパスに加えて可能であればシステムの証明書ストアも使います。デフォルトは`@system`です。

MacのBathyScapheやThousandのように、システムのプロクシ設定を利用し独自のプロクシ設定が不可能な場合は、付属の`proxy.pac`のようなプロクシ設定ファイルを使うと良いかと思います。
最近のOSX(10.10だけ?)では、同じドメインのサーバに対して既にキープアライブ状態の接続があるとプロクシ経由での接続を行ってくれないらしく、そのような場合は`proxy_yosemite.pac`のようにプロクシ経由にするアドレスを増やしてみるといいかもしれません (究極的には全ての2ch.net/bbspink.com向けの接続をプロクシ経由にすれば解決するはず)。

なおOSX 10.11.5以降では、安全性のためにpacファイルに完全な(ドメイン名以降のファイルパスを含む)URLが渡されない仕様になったらしく、urlのマッチングを使用したpacファイルは機能しません。`proxy_10.11.5.pac`のように2ch.net/bbspink全体を対象にするか、各ブラウザが独自にプロクシ設定に対応することを期待する以外ないようです。

## 注意
`--no-direct-dat`指定時にread.cgi経由で生成されるdatは、主に半角スペースの個数を厳密に再現できないために直接取得するdatと細部が異なります。そのため、一度取得したことのあるスレッドに対してread.cgi経由と直接取得を切り替えて差分取得を行う場合、不整合が起こる可能性があります。この場合、一度ログを削除して再取得を試みてください。

`-s`オプションを指定した場合、使用するlibcurlがTLS/SSL対応でビルドされている必要があります。libcurlがバージョン1.1.0未満のOpenSSLもしくはバージョン2.9未満のLibreSSLを使う場合、スレッドセーフを保証するためにロック処理を行う関数を明示的に設定する必要がありますが、proxy2chはこれを行いません。これが原因でクラッシュが発生する可能性があるので、該当するバージョンのOpenSSL/LibreSSLをどうしても使わなければならない場合は[これ](https://github.com/curl/curl/blob/curl-8_1_2/docs/examples/opensslthreadlock.c)を参考にロック処理を実装してください。

## Luaについて
`--bbscgi-lua`オプションを使うためにはLua (LuaJITも可) のヘッダ類を用意した上で`USE_LUA`マクロを定義してビルドし、libluaにリンクする必要があります。このオプションを使わないのであればLuaは不要です。

## MITMモードについて
今の所実験的な機能です。`-c`オプションでhttpsプロクシを有効にした上でMITMモードを有効にするとhttpsなリクエストに介入することが可能になります。有効にするにはビルド時に`USE_MITM`マクロを定義する必要があります。WindowsやMacにおいてもビルドにはOpenSSL (LibreSSL含む) , GnuTLS, wolfSSL, mbedTLSのいずれかのヘッダ・ライブラリ類が必要です。OpenSSL以外をバックエンドに使う場合はそれぞれ`USE_GNUTLS`, `USE_WOLFSSL`, `USE_MBEDTLS`マクロを定義した上でビルドしてください。

OpenSSLを使う場合は1.1.1以降のバージョンを推奨します。3.0以降ではデフォルトではSHA-1を使う暗号スイートが低セキュリティとみなされており、JaneStyle等の古いOpenSSLに依存したアプリとのハンドシェイクが成立しません。そのため、セキュリティレベルを下げることで互換性の改善を行っています。この措置が不要な場合は`OPENSSL_NO_SECURITY_DOWNGRADE`マクロを定義してビルドを行ってください。

wolfSSLを使う場合は`wolfssl/options.h`で定義される機能マクロ`WOLFSSL_CERT_GEN`,`WOLFSSL_CERT_EXT`,`WOLFSSL_ALT_NAMES`が有効な状態でビルドされたものが必要です。デフォルトでは最低限の機能以外は無効化された状態でビルドされるため注意が必要です。おそらく3.12.0以降のバージョンで`configure`に適切なオプション (`--enable-certgen --enable-certext ENABLED_ALTNAMES=yes`) を与えてビルドしたものであれば使えるはずですが細かい検証はしていません。proxy2ch自体はwolfSSLのOpenSSL互換レイヤは必要としませんが、curlのバックエンドにwolfSSLを使う場合は一部の互換API群 (機能マクロ`OPENSSL_EXTRA`) を有効にしないとビルドが通らないようです。

`USE_ECDSA_KEY`マクロを定義してビルドすると署名にRSA (2048bit) ではなくECDSA (P-256) を使うようになります。サーバ側の処理がRSAに比べて高速 (OpenSSLでのベンチマークでは数十倍の差) なので、貧弱なマシンで動作させる場合はCPU負荷が有意に小さくなる可能性があります。ただし、クライアントが古いOSで動作している場合は対応していない可能性があります。OSレベルでの対応状況はWindowsはVista以降、MacOSは10.6以降、iOSは4以降、Androidは4以降で対応のようです。

## `--manage-bbscgi-cookies`オプションについて
5ch/bbspinkへの投稿に関係するクッキーをproxy2ch側で管理/処理します。curlのcookie engineを利用しており、libcurlのバージョンが7.77.0未満の場合は一度有効にしたcookie engineを無効化できないという問題があるため利用できません。

オプション有効時はブラウザ側に`Set-Cookie`ヘッダは透過的に送られますが、ブラウザ側からの`Cookie`ヘッダはBeやUplift関係のものを除いて無視されます。クッキーはUser-Agentごとに独立して管理されるため、User-Agentを変更すると使用するクッキーも変わります。`--keystore`オプションで指定したファイルがクッキーの永続的な保管庫として利用され、指定しなかった場合はproxy2chを終了した時点で全てのクッキーは破棄されます。

webブラウザから`http://localhost:9080/5ch/cookies`にアクセスすることでproxy2chの管理下にあるクッキーの閲覧と削除が可能です。また、`http://localhost:9080/5ch/accounts`にアクセスすることでどんぐりシステム/be/UPLIFTアカウントのログインが可能です。一度ログインすると約12時間後を目安に再ログインします。

ログイン/ログアウトをスクリプト等で自動化したい場合、`http://localhost:9080/5ch/accounts`に対して以下のパラメータを`application/x-www-form-urlencoded`形式でPOSTしてください。

* `service` : `donguri`, `be`, `uplift` のいずれか
* `action` : `login`, `logout` のいずれか
* `mail` : メールアドレス (`action`が`logout`の場合は不要)
* `pass` : パスワード (`action`が`logout`の場合は不要)

curlでログインする場合は例えば`curl -d "service=donguri" -d "action=login" --data-urlencode "mail=foo@example.com" --data-urlencode "pass=my-secret-password" http://localhost:9080/5ch/accounts`とします。

`localhost:9080`のポート番号の部分はデフォルトの9080番で待ち受けている場合の話です。`-p`で変更している場合は適宜読み替えてください。なお、 `-g`を付けて外部からの接続を受け付けている場合でもlocalhost以外からのアクセスは不可です。

## bbsmenu生成機能について
proxy2chを起動した状態で`http://localhost:9080/5ch/bbsmenu.html`あるいは`http://localhost:9080/5ch/bbsmenu.json`にアクセスするとbbsmenu (板一覧) の取得が可能です。そのままだとmenu.5ch.netのものと同等ですが、以下のクエリパラメータを指定することができます。

* `2ch=true` : リンク先のホストを5ch.netではなく2ch.netにします。
* `https=true` : リンクのスキームをhttpではなくhttpsにします。
* `talk=true` : talkの板へのリンクを含めます。

例えば`http://localhost:9080/5ch/bbsmenu.html?2ch=true&talk=true`などとします。proxy2chはtalkを2ch互換掲示板として閲覧可能にする機能を含んでいるため、板一覧に含めることでブラウザからtalkの板をそのまま開くことができるようになります。ただし、書き込みには有効なAPIキーが必要です。

`localhost:9080`のポート番号の部分はデフォルトの9080番で待ち受けている場合の話です。`-p`で変更している場合は適宜読み替えてください。なお、 `-g`を付けて外部からの接続を受け付けている場合でもlocalhost以外からのアクセスは不可です。

## コンパイル方法
MacとLinux等Un\*xでは、`Makefile`を使います。 
Windows (MinGW/MSYS) の場合、`Makefile.mingw`を使います。
`CMakeLists.txt`があるのでcmakeを利用すれば依存関係を自動解決してくれる可能性が高いです。

Macの場合、たぶんそのままコンパイルできるはずです。  
その他Un\*x系の場合、libcurlとlibiconv、libcrypto(OpenSSL)もしくはGnuTLSが入っていなければ入れましょう。libcurlがSSL/TLS非対応だとAPIに接続できないので注意してください。 
Windowsの場合、MinGW/MSYSだけではライブラリが不足しており、コンパイラが認識するよう各ライブラリ/ヘッダ類を適切にインストールする必要があります。以下にMinGWを用いてWin32向けのバイナリを生成する際に必要なファイルの入手先の例を示します。

* [libcurl](https://curl.se/windows/)
* [pthread](https://sourceforge.net/projects/mingw/files/MinGW/Base/pthreads-w32/pthreads-w32-2.8.0-3/) (MinGWに含まれていない場合)
* [regex](https://packages.msys2.org/base/mingw-w64-libgnurx) (MinGWに含まれていない場合)
* [Lua](https://sourceforge.net/projects/luabinaries/files/) (`--bbscgi-lua`オプションを使いたい場合のみ)
* [OpenSSL](https://packages.msys2.org/base/mingw-w64-openssl) (MITMモードを使いたい場合のみ)
